import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';

interface initConfig {
  id: string;
  autoRotate?: boolean;
}

class ThreeLoader {
  config = {} as initConfig;

  canvas = {} as HTMLCanvasElement;

  gltfLoader = new GLTFLoader();

  camera = {} as THREE.PerspectiveCamera;

  scene = new THREE.Scene();

  renderer = {} as THREE.WebGLRenderer;

  orbitControls = {} as OrbitControls;

  transformControls = {} as TransformControls;

  ambientLight = {} as THREE.AmbientLight;

  currentModel = null as unknown as THREE.Group;

  rendererColor = '#ffffff' as string;

  cameraPosition = new THREE.Vector3(0, 0.1, 4.6)

  constructor(config: initConfig) {
    this.config = config;
    this.animate = this.animate.bind(this);
    let material = new THREE.LineBasicMaterial({
      color: 0xcccccc
    });
    let geometry = new THREE.BufferGeometry().setFromPoints([
      new THREE.Vector3(-10, -.28, 0), // 起始点
      new THREE.Vector3(10, -.28, 0)   // 结束点
    ]);
    let line = new THREE.Line(geometry, material);
    this.scene.add(line);
    this.DRACOLoader();
    this.clearPreviewContainer();
    this.init();
  }
  async setEnvMap(gltf: any) {
    console.log(gltf, 'gltf')
    const rgbeLoader = new RGBELoader();
    const envMap = await rgbeLoader.loadAsync('https://impinxyz-1300023548.cos.ap-guangzhou.myqcloud.com/san_giuseppe_bridge_2k.hdr');
    envMap.mapping = THREE.EquirectangularReflectionMapping;
    gltf.scene.traverse((child:any) =>{
      if(child.isMesh && child.name === '瓶盖'){
        child.material.envMap = envMap;
      }
    })
  }
  init() {
    const threeContent = document.getElementById(this.config.id) as HTMLElement;
    if (!threeContent) return;
    const width = threeContent.offsetWidth;
    const height = threeContent.offsetHeight;
    this.createCamera(width, height);
    this.renderer = new THREE.WebGLRenderer({
      preserveDrawingBuffer: true,
      antialias: true,
    });
    this.renderer.shadowMap.enabled = true;
    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    this.renderer.setSize(width, height);
    this.renderer.setClearColor(this.rendererColor, 1);
    this.initOrbitalControls();
    // this.initTransformControls();
    this.createAmbientLight();
    this.renderer.setAnimationLoop(this.animate);
    threeContent.appendChild(this.renderer.domElement);
  }

  createCamera(width: number, height: number) {
    this.camera = new THREE.PerspectiveCamera(8, width / height, 0.1, 5000);
    this.camera.position.copy(this.cameraPosition)
    this.scene.add(this.camera);
  }

  initOrbitalControls() {
    this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement);
    this.orbitControls.target = new THREE.Vector3(0, 0.3, 0);
    // this.orbitControls.addEventListener('change', () => {
    //   console.log(this.orbitControls.target,'target');
    //   console.log(this.camera.position)
    // })

    this.orbitControls.mouseButtons.MIDDLE = THREE.MOUSE.DOLLY,
    // 监听键盘按下事件，检查是否按下Ctrl
    document.addEventListener('keydown', (event) => {
        if (event.ctrlKey) {
            this.orbitControls.mouseButtons = {
                LEFT: THREE.MOUSE.ROTATE,
                RIGHT: THREE.MOUSE.PAN
            }
            this.orbitControls.enablePan = true
        }
    });
    // 监听键盘抬起事件，恢复控制按钮的默认行为
    document.addEventListener('keyup', () => {
        this.orbitControls.enablePan = false
    });
  }

  initTransformControls() {
    this.transformControls = new TransformControls(this.camera, this.renderer.domElement);
    this.transformControls.enabled = true;
    this.scene.add(this.transformControls);
    
  }
  setTransformAttact(uuid:string){
    this.scene.traverse(item => {
      if(item.uuid === uuid)this.transformControls.attach(item);
    })
    // currentAttact = modelList.find((item:any) => item.uuid === model.uuid);
  }

  setModelAttactInfo(model:any){
    if(this.transformControls.object){
      let object = this.transformControls.object;
      object.position.set(Number(model.position.x), Number(model.position.y), Number(model.position.z))
      object.rotation.set(Number(model.rotation.x), Number(model.rotation.y), Number(model.rotation.z))
      object.scale.set(Number(model.scale.x), Number(model.scale.y), Number(model.scale.z))
    }
  }

  setTransformControlsMode(mode:"scale" | "translate" | "rotate"){
    this.transformControls.setMode(mode);
  }

  createAmbientLight() {
    this.ambientLight = new THREE.AmbientLight(0xffffff, 1.5);
    this.scene.add(this.ambientLight);
  }

  async createPlaneBackGround(floorColor:string, bgurl:string){
    const geoFloor = new THREE.PlaneGeometry( 15, 15 );
    const matFloor = new THREE.MeshPhongMaterial({color:floorColor});
    matFloor.needsUpdate = true;
    const mshFloor = new THREE.Mesh( geoFloor, matFloor );
    mshFloor.rotation.x = - Math.PI / 2;
    mshFloor.receiveShadow = true;
    // mshFloor.castShadow = true;
    this.scene.add( mshFloor );
    const bgFloor = new THREE.PlaneGeometry(2, 1)
    const bgmatFloor = new THREE.MeshPhongMaterial({color:floorColor});
    const textureLoader = new THREE.TextureLoader();
    if(bgurl){
      const texture = await textureLoader.loadAsync(bgurl);
      bgmatFloor.map = texture;
      bgmatFloor.needsUpdate = true;
      const BGmshFloor = new THREE.Mesh( bgFloor, bgmatFloor );
      BGmshFloor.position.y = .47
      BGmshFloor.position.z = -.45
      BGmshFloor.receiveShadow = true;
      this.scene.add( BGmshFloor );
    }
  }
  animate() {
    if(!this.renderer)return
    // this.transformControls.updateMatrixWorld(); // 更新 transformControls世界坐标系
    this.orbitControls.update();

    this.renderer.render(this.scene, this.camera);
    this.orbitControls.enabled = !this.transformControls.dragging;
    // this.scene.rotation.y += 0.01;

    this.config.autoRotate && this.currentModel && (this.currentModel.rotation.y += 0.01);
  }

  loadModel(url: string, progressCb?: Function) {
    return new Promise((resolve, reject) => {
      this.gltfLoader.load(
        url,
        (gltf: GLTF) => {
          gltf.scene.traverse(item => {
            item.castShadow = true;
            item.receiveShadow = true;
          })
          resolve(gltf);
        },
        (pro) => progressCb && progressCb(pro),
        (err) => reject(err),
      );
    });
  }
  removeModel(uuid:string) {
    for(let i = 0; i < this.scene.children.length; i++){
      if(this.scene.children[i].uuid === uuid){
        this.scene.remove(this.scene.children[i]);
        break;
      }
    }
  }

  clearPreviewContainer() {
    const previewContainer: HTMLElement = document.getElementById(this.config.id)!;
    previewContainer.innerHTML = '';
  }
  DRACOLoader() {
    const dracoLoader = new DRACOLoader();
    dracoLoader.setDecoderPath('/draco/');
    dracoLoader.setDecoderConfig({ type: 'js' });
    this.gltfLoader.setDRACOLoader(dracoLoader);
  }
  async setTextureImage(baseUrl: string | undefined, textureName: string, uuid:string) {
    if (!baseUrl) {
      return;
    }
    let imgBit = (await this.base64ToImageBitmap(baseUrl)) as unknown as ImageBitmap;
    let group = {} as THREE.Group;
    this.scene.traverse((child) => {
      if (child instanceof THREE.Group && child.uuid === uuid) {
        group = child;
      }
    });
    if (group) {
      group.traverse(async (child) => {
        if (child instanceof THREE.Mesh && child.name === textureName) {
          let texture = new THREE.Texture(imgBit);
          texture.needsUpdate = true;
          texture.flipY = false; // 上下镜像
          child.material.map = texture;
          texture.colorSpace = THREE.SRGBColorSpace;
        }
      });
    }
  }
  // 清除除环境光外所有灯光
  clearLights() {
    for (let i = 0; i < this.scene.children.length; i++) {
      // const element = array[i];
      if(this.scene.children[i] instanceof THREE.Light && this.scene.children[i].type !== 'AmbientLight'){
        this.scene.children.splice(i, 1);
        i--;
      }
      
    }
  }

  setLightIntensity(uuid:string, intensity:number) {
    this.scene.traverse(item => {
      if(item.uuid === uuid && item instanceof THREE.Light){
        item.intensity = intensity;
      }
    })
  }

  getLight(uuid:string){
    let light = null;
    this.scene.traverse(item => {
      if(item.uuid === uuid && item instanceof THREE.Light){
        light = item;
        return
      }
    })
    return light;
  }

  // 创建平行光
  createLight(data:any){
    const light = new THREE.DirectionalLight(data.color, data.intensity);
    light.position.set(data.position.x, data.position.y, data.position.z);
    light.shadow.mapSize.width=2048;
    light.shadow.mapSize.height=2048;
    light.castShadow = true;
    light.shadow.bias =  -0.00010;
    light.receiveShadow = false
    this.scene.add(light);
    return light;
  }
  setSceneBackground(type: string, value: string) {
    if (type === 'color') {
      this.scene.background = new THREE.Color(value);
      return;
    }
    const textureLoader = new THREE.TextureLoader();
    textureLoader.load(value, (res) => {
      res.needsUpdate = true;
      this.scene.background = res;
    });
  }
  exportImage() {
    return this.renderer.domElement.toDataURL();
  }
  private base64ToImageBitmap(base64String: string) {
    const img = new Image();
    img.src = base64String;
    img.crossOrigin = 'anonymous';
    return new Promise((resolve) => {
      img.onload = async () => {
        resolve(await createImageBitmap(img));
      };
    });
  }
}

export default ThreeLoader;
